              Machine Language Made Easy ! (Part 1)
                          by
                      Lyle Giese
                  DELPHI Mail:  LYLEG
  
This is the first in a series of columns to help ease the newcomer into
the world of Machine Language.  I am still not sure how I got into this
job, but I will give it my best!

It is quite hard to get started in Machine Language programing, but just
like the BASIC in your first computer, once you know a little about it
is not that difficult.  This column will be based on the 6502 & 6510
microprocessors that are used in the Commodore 64 & Vic-20, Atari
400-600-800 series machines, and in some Apples. The 8500 processor in
the C-128 is a direct cousin of the 6502. All instructions for the 6502
will do the same things on the 8500. The 8500 can do more, but that will
not be covered here.

In starting out with anything that is foreign, it takes time to cover
all the terminolgy needed to understand the simplest instruction.  So,
this month's column will be covering just that, terminology.

I got my 'training' in Machine Language by first reading Richard
Mansfield's book "Machine Language for Beginners". It is, in my opinion,
an excellent book for the novice.  I cannot, however, comment on his
second book as I have not read it.

A book that is on the MUST have list for the C-64 owner is the
'Programmers Reference Guide' (PRG).  It has valuable information on how
to use the Kernal routines inside the C-64. Later, I hope to cover how
to read the Kernal routine charts in the PRG.

Memory maps of the computer you are using are invaluable! Two good ones
for the C-64 are "The Anatomy of the Commodore 64", from Abacus
Software, and "Mapping the C-64" by Sheldon Leeman, from Compute!
Publications.  "The Anatomy of the Commodore 64" has very good
disasemblies of all the ROM routines in the 64.  Sheldon's book is a
good reference for the low memory usage in the 64 and for some comments
on BASIC and the KERNAL.

You will also need a simple assembler and a simple dissambler to use.
There are good Public Domain ones here in the database of the Flagship.
Later, if you want to get more involved in Machine Language, you will
want a more complex assembler.  But again, that is a topic for future
column.

MEMORY.  That is the stuff we want more and more of! But what is memory?
Memory, in its simplest form, is called a "bit."  Common belief has it
that the term bit is short for binary digit, and got its name from that.
A binary digit has only two states, a zero or a one.  Not much power or
information can be stored in one of two digits!  By chaining the bits in
a logical manner, we can use them to store more information.

The next building block we use is a byte.  A byte is 8 bits of memory
used together.  With 8 bits, we  have 256 different combinations of
one's and zero's to work with.

Richard Mansfield used an excellent analogy to explain how memory is
configured.  Imagine the 8 bits as 8 lights in a house. The lights will
be on or off as the bits are turned on or off.  Now, line up number of
houses in a row down a long street.  The first house will have an
address of zero. The second one an address of 1 and so on, until we get
to the end of our street (memory). On the 64 the end will be at 64K.
That is not 64,000.  A K of memory is 1024.  That number is used partly
because it is a factor of 2 (2 to the power of 10).  This means the last
house in memory will have an address of 65,535 (remember that we started
with an address of zero).  Remember, I said that a byte can hold 256
different bit combinations?  Since that is what a byte can handle,
memory is again divided into 256 byte chunks, or blocks on our street,
called pages.

Zero page, besides being the first page, is special. Because the page is
zero, the microproccessor is set up to be able to access zero page
faster.  The reason is that in order to access memory we have to use the
address of the byte of memory. The address is divided into two bytes
called the "least significant byte" (LSB) and the "most significant
byte" (MSB).  When talking about the bytes in zero page, the MSB will be
zero. So a special set of instructions were set up inside the 6502 to
work with zero page. These instructions work faster because the
processor fetches one less byte in order to find the address. That fact
was not lost on Commodore when they designed their computers. They made
heavy use of zero page.

Another thing that you will find is the heavy use of Hexidecimal
notation.  This is a numbering system based on 16 digits instead of 10
used in decimal that we are used to. Hexidecimal, or hex for short, uses
0-9, and A-F for its digits, with A=10, B=11, etc.  Hex is normally
prefixed by a "$" as $10, which is 16 in decimal.  It is sometimes
written as 10h, but that is seldom seen anymore.

Hex is convenient for use with byte sized memory as 2 digits are all
that are needed to show the maximum value that a byte can hold (ranging
from $00 to $FF(255)). Four digits are all that are needed to designate
memory locations in a 64k machine. That is two bytes can range from
$0000 to $FFFF ( or 65,535). I strongly suggest that you become familar
with hex as it is used often in articles or books written about ML.

The hex designation for memory locations can be split very easily. In
the example above, $FFFF, the LSB will hold $FF and the MSB will hold
$FF.  Note: the MSB also refers to the page number when talking about
memory locations.

At this point, you have to know something about what is inside your
microprocessor.  There is a little Random Access Memory (RAM) and the
instructions, contained in Read Only Memory (ROM)-like memory.

The RAM memory is divided into 'registers': the A register, commonly
called the Accumlator; X register; Y register] Stack Pointer (SP);
Program counter (PC); and the Status Register (SR), also called the P
register. Each register has its own special properities and/or functions
that enable it to do certain tasks that other registers cannot do.

I will be using the term 6502 even though everything applies equally to
the 6510 and 8500 unless otherwise noted.

The A reg is where all the math functipms of the 6502 are done. In order
to add, subtract, or do logical functions, one number has to be in the
accumlator.

The X nd Y registers are use for inexing, but they do have some
different proporties.  The differences re subtle and I will cover them
in a later column.

The PC is used to keep track of where we are in the program so that the
6502 will know where to get its next instruction.

The SP is a pointer to the Stack in memory.  This is used to store the
return address when you JSR (Jump with Return - similar to GOSUB in
BASIC).  The stack may also be used for temporary storage, but this
applicaiont should be left to advanced programmers.

The P reg, or Status Reg, is used to keep track of certain conditions
that happened in the last operation.  Did the last operation result in a
zero result? Did the last addition cause a carry?  Did the last
subtraction use a borrow?  In the P reg, 7 flags that are used for this
purpose.  I will cover them in a later column.

With an article on anything new, it is very helpful to show a working
example. ML is no exception to that rule. In this vain I thought we
would do something simple, change the color memory on the C-64. In case
some of you have forgotten in the Version2 Kernal C-64 a clear screen
caused the 64 to set the background color memory to the current
foreground color. So if then you wanted to poke to the screen, you
couldn't see it as the character was the same color as the foreground.

We would need to fill color memory with something other than the
foreground color. On the 64 the default foreground color is blue, which
has a color number of 6. We need to change it to some other number. We
could do that in BASIC with a for-next loop but that takes much too
long. In ML it is a short and simple operation.

With this example, I will use the convections used with Supermon. That
program is in the PD and was included on the disk bonus pack inside the
1541. So we will start this project by loading and running Supermon
(most other simple monitors use very simular syntax).

The first thing you will see is a status line. That shows you the
contents of all the 6502 registers, starting with the Program
counter(PC), IRQ vector(this are the routines that service the keyboard
and TOD clocks and other things and occurs approx every 60th of a
second), the Status Reg(SR also called the P reg), the A reg(or
Accumlator, the X reg, the Y reg and the Stack pointer. Then a period on
the next line. The period replaces the cursor.

Here's a printout of our program and I will explain.
  
.A C000 LDY #$D8
.A C002 STY $FF
.A C004 LDY #$00
.A C004 STY $FE
.A C006 STY $FE
.A C008 LDA #$00
.A C00A STA ($FE),Y
.A C00C INY
.A C00D BNE $C00A
.A C00F INC $FF
.A C011 LDA $FF
.A C013 CMP #$DC
.A C015 BNE $C008
.A C017 RTS
.A C018
  
After the period, we type an A. This tells the program to start
assembling want we type in. Next we type in the starting address in HEX.
In this example we use $C000, which is 49152 decimal. This a free zone
that BASIC does use and is quite frequently used for ML subroutines and
programs, like CBM's Wedge program.

Next (we are still on the first line) we type in the mnemonic for the
instruction we want exicuted. In this case the Op code is LDY which
means LoaD the Y reg. The #$D8 is called the arugment. The '#' use the
number that follows(as oppsed to treating it as an address). So it is
telling us to LoaD the Y reg with the number $D8. This method of
adressing is called immediate. Now we press the <CR> and you have put
your first instruction into memory!

After the <CR> the computer will respond with '.A C002'. After you give
the assembler the start address it will figure out where the next
instruction goes for you. If this was the end of the program we would
just answer by typing a <CR>.

The second op code is Store The Y reg. Now all the store and load
instructions actually copy the information from one place to another
without destroying the orignal. So in this case (without the '#' means
that we treat the argument as an address) we will store (or copy) the
contents of the Y reg into memory location $FE. By the way this
addressing mode is called zero page absolute, absolute because we are
specifing the exact adress to use and zero page because the address is
in zero page.

The next two instructions are the same as above except we will put $00
into memory location $FE. In case you have not noticed we have put
address $D800 into $FE & $FF. The adress $D800 is the start of color
memory at 55296 decimal.

But HEY Wait A Minute!!! Didn't you just put the adress in backwards??
Yes we did but that is the way the 6502 expects to find all of its
adress. LSB first then the MSB. I don't know why but that is the way it
is in the 6502, adresses are stored in memory backwards.

The next instruction tells us to LoaD the A reg with something. The
argument tells what. In this case the '#' again tells us to use this
number and not treat it as an address. By the way this is called the
immediate addressing mode. So we put the number $01 into the A reg,
which is the color number for white. By changing this number we could
fill color memory with any of the 16(0-15) colors.

Now we want to put the color number into the color memory. This next
instruction does that for us. We are going to STore the A reg, but
where? Well, the parenthasis around the $FE tells us that $FE is not the
target address but that we will find the target contained in memory
locations $FE & $FF(which we set to $D800 earlier).

Now what do we do with the ',Y"? We take the adress found at $FE &
$FF($D800) and add the Y reg to it. The first time through this routine
the Y reg contains $00. So we will STore the A reg at $D800+0 or at
$D800. This is a very useful adressing mode called indirect Y, you will
use it often!

In the next instruction, we INcrement the Y reg or add 1 to it. This
adressing mode is called implied. I guess it got its name because the
argument does not need to be specified or is implied.

The next instruction is an important one. It stands for Branch if Not
Equal. Not equal to what? Well the instruction checks the Zero flag in
the Status reg. When the previous instruction (in this case INY) results
in a zero result or equals the zero flag is set in the Status reg. If we
just keep increment the Y reg, how will that ever be equal to zero?

Good question! Earlier in this column I stated that a byte could only
hold a number from $00-$FF(255). The registers in the 6502 are only 1
byte long, except the PC which is 2 bytes long. So what happens when the
Y reg holds $FF(255) and we increment or add one to it? It cann't hold a
bigger number, so it rolls over to $00, but when that happens it sets
the zero flag in the Status reg.

Back to the instruction Branch if Not Equal to zero. If the Y reg is not
zero then we go back to $C00A. Now the Y reg holds a $01 and we will add
the address found at $FE-$FF to the contents of the Y reg and get
$D800+1 or $D801. So the contents of the A reg is now copyed into $D801
or the second byte in color memory.

This of course continues until the Y reg rolls over to zero. Then you
fall through to $C00F. The instruction there is INCrement (no '#') the
number in memory location $FF. Then we will LoaD the A reg with that
value. The first time we hit this we will be going from $D8 to $D9.

Now that we have that value in the A reg we can CoMPare it to something,
(Note the '#' which means that we compare to the number $DC not memory
location $DC). Why $DC? That's above our color memory. When we are at
$DB, we still have some of our color memory there and need to fill it up
with our color number.

The next instruction is the Branch if Not Equal, which again checks the
zero flag. This time the zero flag was set or not set according to the
outcome of the CoMPare instruction at $C013. During that compare if the
A reg contained the number $DC then the zero flag was set, telling that
they were equal.

And the last instruction is ReTurn for Subroutine. This is just like the
return found in BASIC. What do we do know? The computer asked me to
assemble an instruction at $C018. We tell the assembler in Supermon that
we are done by a <CR> alone.

Now how do we run the program? It is in memory that is not directly used
by BASIC and besides it is not a BASIC program! Well, there are two ways
to do that at this point. The first one is after the period to type
'G'(for Go) and C000<CR>. That tells Supermon to go to $C000(which is
where we put our program) and try to execute our instructions there.(I
emphsize try because sometimes typing errors do happen!).

The other way is to exit to BASIC by type 'X' at the period, which eXits
the  monitor and returns us to BASIC. Then 'SYS49152'. This tells BASIC
to try to execute the ML program we put at $C000.

And if all went well, all of our letters on the screen will turn white
and the prompt 'READY' will apear(or a period if we were still in
Supermon).

Well, that's alot ot digest and I hope I didn't lose anyone, but if you
did get lost along send me a note and I will try to sort it out for you!
